package com.brycen.nio.file;

import org.junit.Test;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;

public class PathAndFileTest {

    /**
     * Path 用来表示文件路径
     * Paths 是工具类，用来获取 Path 实例
     *
     * Path source1 = Paths.get("1.txt"); // 相对路径 不带盘符 使用 user.dir 环境变量来定位 1.txt
     * Path source2 = Paths.get("d:\\1.txt"); // 绝对路径 代表了  d:\1.txt 反斜杠需要转义
     * Path source3 = Paths.get("d:/1.txt"); // 绝对路径 同样代表了  d:\1.txt
     * Path projects = Paths.get("d:\\data", "projects"); // 代表了  d:\data\projects
     */
    @Test
    public void testPath(){
        Path path = Paths.get("d:\\data\\projects\\a\\..\\b");
        //d:\data\projects\a\..\b
        System.out.println(path);
        //d:\data\projects\b
        System.out.println(path.normalize()); // 正常化路径 会去除 . 以及 ..

    }


    /**
     * 判断文件是否存在
     */
    @Test
    public void testExistsFile(){
        Path path = Paths.get("helloword/data.txt");
        //输出绝对路径：E:\gitcode\NIODemo\helloword\data.txt
        System.out.println(path.toAbsolutePath());
        //false
        System.out.println(Files.exists(path));
    }

    /**
     * 创建目录
     */
    @Test
    public void testCreateDirectory() throws IOException {
        Path path = Paths.get("helloword/d1");
        //创建一级目录
//        Files.createDirectory(path);
        //创建多级目录
        Files.createDirectories(path);
        System.out.println(path.toAbsolutePath());
    }

    /**
     * 拷贝文件
     */
    @Test
    public void testCopyFile() throws IOException {
        Path source = Paths.get("helloword/data.txt");
        Path target = Paths.get("helloword/target.txt");
        //拷贝文件，如果文件已存在，会抛异常 FileAlreadyExistsException
        Files.copy(source, target);
        //如果希望用 source 覆盖掉 target，需要用 StandardCopyOption 来控制
//        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    }

    /**
     * 移动文件
     */
    @Test
    public void testMoveFile() throws IOException {
        Path source = Paths.get("helloword/data.txt");
        Path target = Paths.get("helloword/target.txt");
        //StandardCopyOption.ATOMIC_MOVE 保证文件移动的原子性，同时如果文件存在会覆盖掉
        Files.move(source, target,StandardCopyOption.ATOMIC_MOVE);
    }

    /**
     * 删除文件
     */
    @Test
    public void testDeleteFile() throws IOException {
        Path target = Paths.get("helloword/target.txt");
        //如果删除的是文件，并且文件不存在，会抛异常 NoSuchFileException
        //如果删除的是目录，并且里面还有内容，会抛异常 DirectoryNotEmptyException
        Files.delete(target);
    }

    /**
     * 遍历路径下的文件夹和文件
     *
     * 可以使用Files工具类中的walkFileTree(Path, FileVisitor)方法，其中需要传入两个参数
     *      Path：文件起始路径
     *      FileVisitor：文件访问器，使用访问者模式
     *
     * FileVisitor接口的实现类SimpleFileVisitor有四个方法
     *      preVisitDirectory：访问目录前的操作
     *      visitFile：访问文件的操作
     *      visitFileFailed：访问文件失败时的操作
     *      postVisitDirectory：访问目录后的操作
     */
    @Test
    public void TestWalkFileTree() throws IOException {
        Path path = Paths.get("helloword");
        // 文件目录数目
        AtomicInteger dirCount = new AtomicInteger();
        // 文件数目
        AtomicInteger fileCount = new AtomicInteger();
        Files.walkFileTree(path, new SimpleFileVisitor<Path>(){
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                System.out.println("===>"+dir+": 进入目录");
                // 增加文件目录数
                dirCount.incrementAndGet();
                return super.preVisitDirectory(dir, attrs);
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                System.out.println("<==="+dir+": 退出目录");
                return super.postVisitDirectory(dir, exc);
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                System.out.println(file);
                // 增加文件数
                fileCount.incrementAndGet();
                return super.visitFile(file, attrs);
            }
        });
        // 打印数目
        System.out.println("文件目录数:"+dirCount.get());
        System.out.println("文件数:"+fileCount.get());
    }
}
